Odklenite moč useRef v Reactu. Raziščite različne primere uporabe, vključno z neposrednim dostopom do DOM-a, ohranjanjem spremenljivih vrednosti in optimizacijo.
React useRef: Obvladovanje vzorcev shranjevanja spremenljivih vrednosti
useRef je močan hook v Reactu, ki omogoča ohranjanje vrednosti med ponovnimi upodobitvami (renderji), ne da bi povzročil ponovno upodobitev ob spremembi teh vrednosti. Pogosto ga povezujemo z neposrednim dostopom do elementov DOM, vendar njegove zmožnosti segajo veliko dlje. Ta celovit vodnik se bo poglobil v različne primere uporabe useRef in vam omogočil pisanje učinkovitejše in lažje vzdrževane kode v Reactu.
Razumevanje useRef: Več kot le dostop do DOM-a
V svojem bistvu useRef vrne spremenljiv referenčni objekt, katerega lastnost .current je inicializirana s posredovanim argumentom (initialValue). Vrnjeni objekt bo obstal skozi celotno življenjsko dobo komponente. Ključno je, da spreminjanje lastnosti .current ne sproži ponovne upodobitve. To je glavna razlika med useRef in useState.
Čeprav je dostop do elementov DOM pogost primer uporabe, se useRef odlično obnese pri upravljanju katere koli spremenljive vrednosti, ki ob posodobitvi ne sme povzročiti ponovne upodobitve. Zaradi tega je neprecenljiv za naloge, kot so:
- Shranjevanje prejšnjih vrednosti propsov ali stanj.
- Vzdrževanje števcev ali časovnikov.
- Sledenje stanju fokusa brez povzročanja ponovnih upodobitev.
- Shranjevanje katere koli spremenljive vrednosti, ki mora obstati med upodobitvami.
Osnovna uporaba: Dostop do elementov DOM
Najbolj znan primer uporabe je neposreden dostop do elementov DOM. To je uporabno v scenarijih, kjer morate imperativno komunicirati z vozliščem DOM, na primer za fokusiranje vnosnega polja, merjenje njegovih dimenzij ali sprožanje animacij.
Primer: Fokusiranje vnosnega polja
Tukaj je primer, kako lahko uporabite useRef za fokusiranje vnosnega polja, ko se komponenta vklopi (mount):
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Focus the input field on mount
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Empty dependency array ensures this runs only once on mount
return (
<input type="text" ref={inputRef} placeholder="Enter text" />
);
}
export default MyComponent;
Razlaga:
- Ustvarimo referenco (ref) z
useRef(null). Začetna vrednost jenull, ker vnosni element ob prvi upodobitvi komponente še ne obstaja. - Referenco pripnemo na vnosni element z uporabo propsa
ref:ref={inputRef}. React bo samodejno nastavilinputRef.currentna vozlišče DOM, ko bo vnosni element vklopljen. - Uporabimo
useEffects prazno matriko odvisnosti ([]), da zagotovimo, da se efekt izvede samo enkrat po vklopu komponente. - Znotraj efekta preverimo, ali
inputRef.currentobstaja (da se izognemo napakam, če element še ni na voljo), in nato pokličemoinputRef.current.focus(), da fokusiramo vnosno polje.
Onkraj dostopa do DOM-a: Upravljanje spremenljivih vrednosti
Prava moč useRef leži v njegovi zmožnosti shranjevanja spremenljivih vrednosti, ki obstanejo med ponovnimi upodobitvami, ne da bi jih sprožile. To odpira širok spekter možnosti za optimizacijo delovanja komponent in upravljanje stanj v funkcijskih komponentah.
Primer: Shranjevanje prejšnjih vrednosti propsov ali stanj
Včasih morate dostopiti do prejšnje vrednosti propsa ali spremenljivke stanja. useRef ponuja čist način za to, ne da bi sprožili nepotrebne ponovne upodobitve.
import React, { useRef, useEffect } from 'react';
function MyComponent({ value }) {
const previousValue = useRef(value);
useEffect(() => {
// Update the ref's .current property with the current value
previousValue.current = value;
}, [value]); // Effect runs whenever the 'value' prop changes
// Now you can access the previous value using previousValue.current
return (
<div>
Current value: {value}
<br />
Previous value: {previousValue.current}
</div>
);
}
export default MyComponent;
Razlaga:
- Inicializiramo referenco
previousValuez začetno vrednostjo propsavalue. - Uporabimo
useEffectza posodobitev lastnostipreviousValue.currentvsakič, ko se propsvaluespremeni. - Znotraj komponente lahko zdaj dostopamo do prejšnje vrednosti propsa
valuez uporabopreviousValue.current.
Primer uporabe: Sledenje spremembam v odzivih API-ja (mednarodni scenarij)
Predstavljajte si, da gradite nadzorno ploščo, ki prikazuje menjalne tečaje, pridobljene iz API-ja. API lahko vrne tečaje v različnih formatih ali z različno natančnostjo, odvisno od vira podatkov (npr. API Evropske centralne banke v primerjavi z API-jem finančne institucije iz jugovzhodne Azije). Z useRef lahko sledite prejšnjemu menjalnemu tečaju in prikažete vizualni indikator (npr. zeleno puščico navzgor ali rdečo puščico navzdol), ki kaže, ali se je tečaj od zadnje posodobitve povečal ali zmanjšal. To je ključnega pomena za mednarodne uporabnike, ki se na te tečaje zanašajo pri finančnih odločitvah.
Primer: Vzdrževanje števcev ali časovnikov
useRef je popoln za upravljanje števcev ali časovnikov, ki ne smejo sprožiti ponovnih upodobitev. Na primer, lahko ga uporabite za sledenje števila klikov na gumb ali za implementacijo preprostega časovnika.
import React, { useRef, useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const clickCount = useRef(0); // Initialize the ref with 0
const handleClick = () => {
clickCount.current++; // Increment the ref's .current property
setCount(clickCount.current); //Increment state which re-renders.
};
return (
<div>
<p>Button clicked: {count} times</p>
<button onClick={handleClick}>Click me</button>
</div>
);
}
export default MyComponent;
Razlaga:
- Inicializiramo referenco
clickCountz vrednostjo 0. - V funkciji
handleClickpovečamo vrednost lastnosticlickCount.current. To ne sproži ponovne upodobitve. - Posodobimo tudi stanje 'count', kar sproži ponovno upodobitev.
Primer: Implementacija funkcije Debounce
Debouncing je tehnika, ki se uporablja za omejevanje pogostosti izvajanja funkcije. Pogosto se uporablja v iskalnih poljih za preprečevanje prekomernih klicev API-ja med tipkanjem uporabnika. useRef se lahko uporablja za shranjevanje ID-ja časovnika, uporabljenega v funkciji debounce.
import React, { useState, useRef, useEffect } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const timerRef = useRef(null); // Store the timer ID
const handleChange = (event) => {
const newSearchTerm = event.target.value;
setSearchTerm(newSearchTerm);
// Clear the previous timer if it exists
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// Set a new timer
timerRef.current = setTimeout(() => {
// Simulate an API call
fetch(`https://api.example.com/search?q=${newSearchTerm}`)
.then(response => response.json())
.then(data => setResults(data.results));
}, 300); // Debounce for 300 milliseconds
};
return (
<div>
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={handleChange}
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
export default MyComponent;
Razlaga:
- Uporabimo
useRefza shranjevanje ID-ja časovnika vtimerRef. - V funkciji
handleChangepočistimo prejšnji časovnik (če obstaja) z uporaboclearTimeout(timerRef.current). - Nato nastavimo nov časovnik z
setTimeoutin shranimo ID časovnika vtimerRef.current. - Klic API-ja se izvede šele, ko uporabnik preneha tipkati za 300 milisekund.
Premisleki glede internacionalizacije: Pri implementaciji debouncinga s klici API-ja, ki vključujejo prikaz informacij v različnih jezikih, zagotovite, da vaš API podpira internacionalizacijo in vrača podatke v želenem jeziku uporabnika. Razmislite o uporabi glave Accept-Language v vaših zahtevah API-ju.
Primer: Sledenje stanju fokusa brez ponovnih upodobitev
Z useRef lahko sledite, ali ima element fokus, ne da bi povzročili ponovne upodobitve. To je lahko uporabno za stiliziranje elementov glede na njihovo stanje fokusa ali za implementacijo lastne logike upravljanja fokusa.
import React, { useRef, useState } from 'react';
function MyComponent() {
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef(null);
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
return (
<div>
<input
type="text"
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<p>Input is focused: {isFocused ? 'Yes' : 'No'}</p>
</div>
);
}
export default MyComponent;
useRef proti useState: Izbira pravega orodja
Pomembno je razumeti ključne razlike med useRef in useState, da izberete pravo orodje za nalogo.
| Lastnost | useRef | useState |
|---|---|---|
| Sproži ponovno upodobitev | Ne | Da |
| Namen | Shranjevanje spremenljivih vrednosti, ki ne smejo sprožiti ponovnih upodobitev. Dostop do elementov DOM. | Upravljanje stanja, ki mora sprožiti ponovne upodobitve. |
| Obstojnost | Obstane med ponovnimi upodobitvami. | Obstane med ponovnimi upodobitvami, vendar se vrednost posodablja z uporabo funkcije za nastavljanje (setter). |
Najboljše prakse in pogoste napake
- Ne spreminjajte stanja neposredno: Čeprav
useRefomogoča neposredno spreminjanje vrednosti, se izogibajte neposrednemu spreminjanju spremenljivk stanja, ki jih upravljauseState. Za posodabljanje stanja vedno uporabite funkcijo za nastavljanje (setter), ki jo zagotavljauseState. - Bodite pozorni na stranske učinke: Ko uporabljate
useRefza upravljanje vrednosti, ki vplivajo na uporabniški vmesnik, bodite pozorni na možne stranske učinke. Zagotovite, da se vaša koda obnaša predvidljivo in ne vnaša nepričakovanih hroščev. - Ne zanašajte se na
useRefza logiko upodabljanja: Ker spremembeuseRefne sprožijo ponovnih upodobitev, se ne zanašajte neposredno na njegove vrednosti za določanje, kaj naj se upodobi. Za vrednosti, ki morajo poganjati logiko upodabljanja, uporabiteuseState. - Upoštevajte vpliv na zmogljivost: Čeprav lahko
useRefpomaga optimizirati zmogljivost s preprečevanjem nepotrebnih ponovnih upodobitev, se zavedajte, da lahko prekomerna uporaba spremenljivih vrednosti oteži razumevanje in odpravljanje napak v kodi.
Napredni primeri uporabe in vzorci
Ohranjanje vrednosti med instancami komponente
Medtem ko `useRef` ohranja vrednosti med ponovnimi upodobitvami *ene same* instance komponente, včasih potrebujete, da vrednost obstane med *različnimi* instancami iste komponente. To zahteva nekoliko drugačen pristop, pogosto z uporabo spremenljivke na ravni modula v kombinaciji z `useRef`.
// myComponent.js
let globalCounter = 0; // Module-level variable
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const counterRef = useRef(globalCounter); // Initialize with the global value
useEffect(() => {
// Update the global counter whenever the ref changes
globalCounter = counterRef.current;
}, [counterRef.current]);
const increment = () => {
counterRef.current++;
//No setState needed, so no re-render
};
return (
<div>
<p>Counter: {counterRef.current}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default MyComponent;
Pomembni premisleki: Ta vzorec uvaja globalno spremenljivko, zato bodite izjemno previdni glede možnih stranskih učinkov in tekmovalnih pogojev (race conditions), zlasti v kompleksnih aplikacijah. Razmislite o alternativnih pristopih, kot je uporaba ponudnika konteksta (context provider), če je treba vrednost deliti med več komponentami na bolj nadzorovan način.
Zaključek: Sprostitev moči useRef
useRef je vsestransko orodje v Reactu, ki presega zgolj dostop do elementov DOM. Z razumevanjem njegove zmožnosti shranjevanja spremenljivih vrednosti brez sprožanja ponovnih upodobitev lahko optimizirate svoje komponente, učinkoviteje upravljate stanje ter gradite zmogljivejše in lažje vzdrževane aplikacije v Reactu. Ne pozabite ga uporabljati preudarno in vedno upoštevajte potencialne kompromise med zmogljivostjo in jasnostjo kode.
Z obvladovanjem vzorcev, opisanih v tem vodniku, boste dobro opremljeni za izkoriščanje polnega potenciala useRef v svojih projektih React, ne glede na to, ali gradite preprosto spletno aplikacijo ali kompleksen poslovni sistem. Pri gradnji za globalno občinstvo ne pozabite upoštevati internacionalizacije in dostopnosti!